/****************************************************************************
*
* Description: Memory regions manager
* Created at: 14.11.06 02:58:02 UTC
*
* $Revision$
*
****************************************************************************/
#pragma once

#if !defined(__common_memory_manager_h__)
#define __common_memory_manager_h__

#include <vector>
#include <ostream>
#include <iomanip>
#include <common/exception.h>
#include <common/resource.h>
#include <common/memory_block.h>
#include <common/memorypredicates.h>
#include <common/singleton.h>

namespace common {
namespace memory {

/* Defines module specific exception.  */
DEFINE_NEW_ERROR(block_not_found);

/* Memory manager is "global" system object that control all memory blocks.  */
template <
    typename mem_traits,
    class    mem_storage = std::vector<mem_traits>
>
class basic_memory_manager
	: public resource_t
{
public:
    typedef basic_memory_block<mem_traits, mem_storage>	region_t;
    typedef std::list<region_t>                     	container_t;

    static const    uint32	id;

    /* Default ctor.  */
    basic_memory_manager ()
    	: resource_t(id)
    {}

    /* Dtor.  */
    virtual ~basic_memory_manager ()
    {}

    /* Determines if two linear memory ranges intersect.  */
    bool is_intersect (addr_t la, size_t ls, addr_t ra, size_t rs) const
    {
        return (la < ra ? (la + ls) > ra : (ra + rs) > la);
    }

	/* Determines if two linear memory ranges intersect.  */
    bool is_intersect (region_t& l, region_t& r) const
    {
        return is_intersect(l.base(), l.size(), r.base(), r.size());
    }

    /* Create new memory block with specified base and size and put to the common blocks list.  */
    region_t& create_block (addr_t start, size_t size)
    {
        blocks_.push_back(region_t(start, size));
        return blocks_.back();
    }

	/* Return block with specified base address.  */
    region_t& get_block (addr_t start)
    {
        container_t::iterator i = find_if(blocks_.begin(), blocks_.end(), base_eq<region_t>(start));
        if (i == blocks_.end())
            THROW(block_not_found, "Block not found\n");

        return *i;
    }

	/* Return block that contain specified address.  */
    region_t& get_block_include_addr (addr_t addr)
    {
        container_t::iterator i = find_if(blocks_.begin(), blocks_.end(), include_addr<region_t>(addr));
        if (i == blocks_.end())
            THROW(block_not_found, "Block not found\n");

        return *i;
    }

	/* Remove block from the memory blocks list.  */
    void remove_block (region_t& block)
    {
        blocks_.remove(block);
    }

    /* Direct access to pool.  */
    container_t& blocks ()
    {
        return blocks_;
    }

    /* Debug stuff.  */
protected:
    /* Dump memory_block into streams.  */
    template <class T>
    class dump_item_str
    {
    public:
        dump_item_str(std::ostream& o)
        	: o_(o)
        {}

        void operator()(T& val)
        {
            o_ << "Block(0x" << std::hex << val.base() << ", 0x" << val.size() << std::dec << ")" << std::endl << val << endl;
        }

    private:
        std::ostream&	o_;
    };

public:
    virtual void dump(std::ostream& o)
    {
        this->resource_t::dump(o);
        for_each(blocks_.begin(), blocks_.end(), dump_item_str<basic_memory_manager<mem_traits, mem_storage>::region_t>(o));
        o << std::endl;
    }

protected:
    container_t blocks_;
};

/* Static members initialization.  */
template <
    typename mem_traits,
    class    mem_storage
>
const uint32 basic_memory_manager<mem_traits, mem_storage>::id = 'mmgr';

/* Declare standard byte-memory manager type.  */
typedef basic_memory_manager<uint8> memory_manager_t;
/* Define standard byte-memory manager object.  */
typedef common::singleton< memory_manager_t > memory_manager;

/* Memory manager singleton helper.  */
#define	MEMORY \
	memory_manager::instance()

} /* End of memory namespace.  */
} /* End of common namespace.  */

#endif  /* End of __common_memory_manager_h__.  */
